#include <iostream>
#include <vector>
#include <string>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sstream>
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h> 
#include <errno.h>

using namespace std;

char pwd[1024];
char myenv[1024];
char* username;//用户名
char Identifier;//用户标识符
int lastcode=0;//最后一个结束的子进程的ID。

void getIdentifier()
{   
    username=getlogin();
    if(username==nullptr)
    {
        Identifier='?';return;
    } 
    if(strcmp(username,"root")==0) Identifier='#';
    else Identifier='$';
}

void getpwd()
{
    getcwd(pwd,sizeof(pwd));
}


 void interact()
 {
    getpwd();
    printf("[%s@VM-4-14-ubuntu]%s%c ",username,pwd,Identifier);
 }

int splitstring(vector<string>& argv)
{
    string tmp;
    //cin>>tmp;
    getline(cin,tmp);
    istringstream iss(tmp);
    string token;
    argv.clear();
    while(iss>>token)
    {
        argv.push_back(token);
    }
    if(argv.empty()) return 0;
    else return argv.size();
}

int buildCommand(char* c_argv[],int argc)
{


    
    //0表示不是内建命令，如果是非0表示是内建命令。
    if(strcmp(c_argv[0],"cd")==0)
    {
        chdir(c_argv[1]);
        getpwd();
        //cd实现的逻辑，稍后处理；
        return 1;
    }
    else if(strcmp(c_argv[0],"echo")==0)
    {
        if(strcmp(c_argv[1], "$?") == 0)
        {
            printf("%d\n", lastcode);
            lastcode=0;
        }
        else if(*c_argv[1] == '$'){
            char *val = getenv(c_argv[1]+1);
            if(val) printf("%s\n", val);
        }
        else{
            printf("%s\n", c_argv[1]);
        }   
        return 1;
    }
    else if(strcmp(c_argv[0],"export")==0)
    {
        strcpy(myenv,c_argv[1]);
        putenv(myenv);
        return 1;
    }
    
    if(strcmp(c_argv[0],"ls")==0)
    {
        c_argv[argc++]="--color";
        c_argv[argc]=nullptr;
    }

    return 0;
}

void NormalExcute(char* c_argv[])
{

    

    // if(access(c_argv[0],F_OK)==-1)
    // {
    //     printf("no such instruction '%s'\n",c_argv[0]);
    //     return;
    // }
    // if(access(c_argv[0],X_OK)==-1)
    // {
    //     printf("No execution permission\n");
    //     return;
    // }

    auto pid=fork();
    if(pid<0)
    {
        perror("fork error");
        return;
    }
    else if(pid==0)
    {
        execvp(c_argv[0],c_argv);
            //命令的合法化检查
        switch(errno) 
        {
            case ENOENT:  // 命令不存在
                printf("%s: command not found\n", c_argv[0]);
                break;
            case EACCES:  // 无权限
                printf("%s: permission denied\n", c_argv[0]);
                break;
            default:
                perror("execvp failed");
        }
        exit(44);
    }
    else
    {
        int status;
        auto rid=waitpid(pid,&status,0);
        if(rid==pid)
        {
            lastcode=WEXITSTATUS(status);
        }
    }

}



int main()
{
    getIdentifier();//获取用户名标识符
    while(1)
    {
        //1.创建互动前缀 
        interact();

        //2.获取字符串
        vector<string> argv;
        int argc=splitstring(argv);
        // if(argc)
        // {
        //     //scf!=0,说明捕获到了某些指令;
        //     for(auto& it:argv)
        //         cout<<it<<" ";
        //     cout<<endl;
        // }
        if(!argc) continue;//scf=0,说明用户什么也没输入直接回车了
            //char* c_argv[32];
        char* c_argv[argv.size()+1];
        int i=0;
        for(;i<argv.size();i++)
        {
            //c_argv[i]=&argv[i][0];不推荐的写法，这样做会导致外部元素直接访问string底层，是危险做法
            c_argv[i]=const_cast<char*>(argv[i].data());//c+17起支持的语法，拷贝一份字符串，对原string没有影响；
        }
        c_argv[i]=nullptr;
        //3.判断指令是不是内建指令
        int n=buildCommand(c_argv,argc);

        //4.判断指令是不是普通指令
        if(!n)
            NormalExcute(c_argv);
    }

    cout<<"END!!!!!!!"<<endl;
    return 0;
}
